////////////////////////////////////////////////////////////////////////////////
//
//  ADOBE SYSTEMS INCORPORATED
//  Copyright 2009 Adobe Systems Incorporated
//  All Rights Reserved.
//
//  NOTICE: Adobe permits you to use, modify, and distribute this file
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package spark.extensions.components.supportClasses {
	/*  
	
		The AutoCompleteController class handles the mouse, keyboard and focus interactions for 
		the AutoComplete control. This class is used by the AutoComplete component to
		handle the opening and closing of the dropdown with contains the suggestions,
		due to user interaction.
		
		@see spark.extensions.components.AutoComplete
		
		@TODO : check handles for every situation of events. 
	
	*  @langversion 3.0
	*  @playerversion Flash 10
	*  @playerversion AIR 1.5
	*  @productversion Flex 4
	
	*/
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	
	import mx.events.SandboxMouseEvent;
	
	import spark.components.TextInput;
	import spark.events.TextOperationEvent;
	import spark.extensions.events.AutoCompleteEvent;
	
	public class AutoCompleteController extends EventDispatcher {	
    /**
     *  Constructor.
     * 
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
		public function AutoCompleteController(){
			super();
		}		
	//--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------
    //----------------------------------
    //  textInputElement
    //----------------------------------
		private var _textInputElement : TextInput;
	/**
     *  A reference to the <code>textInputElement</code> skin part 
     *  of the drop-down component. 
     *         
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
		public function set textInputElement ( v : TextInput ) : void {
			if ( _textInputElement === v ) return;
			if (_textInputElement) _textInputElement.removeEventListener(MouseEvent.CLICK , onTextInputClicked);
			_textInputElement = v;
			_textInputElement.addEventListener(MouseEvent.CLICK , onTextInputClicked);
			_textInputElement.addEventListener(TextOperationEvent.CHANGE , onTextInputChanged);
		}
		/**
		 * @TODO : make this private
		 */
		public function get textInputElement():TextInput{
			return _textInputElement;
		}
		
		private var _prompt : String = '';
		public function set prompt(v:String):void{
			_prompt = v;
		}
		public function get prompt():String{
			return _prompt;
		}
	//----------------------------------
    //  dropDown
    //----------------------------------
		private var _dropDown:DisplayObject;
	/**
     *  A reference to the <code>dropDown</code> skin part      
     *         
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
		public function set dropDown(value:DisplayObject):void {
			if (_dropDown === value) return;
			_dropDown = value;
		}	
		/**
		 * @TODO : make this private
		 */
		public function get dropDown():DisplayObject {
			return _dropDown;
		}
	//----------------------------------
    //  isOpen
    //----------------------------------
    
    /**
     *  @private 
     */
	    private var _isOpen:Boolean = false;
/**
     *  Contains <code>true</code> if the drop down is open.   
     * 
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */  
	    public function get isOpen():Boolean {
	    	return _isOpen;
	    }
	//--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------   

    /**
     *  @private 
     *  Adds event triggers to the textInputElement.
     *
     */ 
	    private function addCloseTriggers():void {
	        textInputElement.systemManager.getSandboxRoot().addEventListener(SandboxMouseEvent.MOUSE_MOVE_SOMEWHERE, systemManager_mouseMoveHandler);
	        textInputElement.systemManager.getSandboxRoot().addEventListener(Event.RESIZE, systemManager_resizeHandler, false, 0, true);
	    }
	     /**
     *  @private
     *  Removes event triggers from the textInputElement.
     *
     */ 
	    private function removeCloseTriggers():void {
	      	textInputElement.systemManager.getSandboxRoot().removeEventListener(SandboxMouseEvent.MOUSE_MOVE_SOMEWHERE, systemManager_mouseMoveHandler);
			textInputElement.systemManager.getSandboxRoot().removeEventListener(Event.RESIZE, systemManager_resizeHandler);	        
	    } 
	/**
     *  Open the drop down and dispatch a <code>AutoCompleteEvent.OPEN</code> event. 
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
	    public function openDropDown():void {
	    	if (!isOpen) {
	    	    addCloseTriggers();
	    		_isOpen = true;	    
	    		textInputElement.text = '';		
	    		dispatchEvent(new AutoCompleteEvent(AutoCompleteEvent.OPEN));
	    	}
	    }	
	/**
     *  Close the drop down and dispatch a <code>AutoCompleteEvent.CLOSE</code> event.  
     *   
     *  @param commit If <code>true</code>, commit the selected
     *  data item. 
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
	    public function closeDropDown(commit:Boolean):void {
	    	if (isOpen) {	
				_isOpen = false;
	        	var dde:AutoCompleteEvent = new AutoCompleteEvent(AutoCompleteEvent.CLOSE, false, true);
	        	if (!commit) dde.preventDefault();
	        	dispatchEvent(dde);
	        	removeCloseTriggers();
	    	}
	    }
    //--------------------------------------------------------------------------
    //
    //  Event handling
    //
    //--------------------------------------------------------------------------
    
     /**
     *  @private
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */ 
	    protected function systemManager_mouseDownHandler(event:Event):void {
	    	if (!dropDown ||  (dropDown && (event.target == dropDown 
	    		 || (dropDown is DisplayObjectContainer && 
	    		 	 !DisplayObjectContainer(dropDown).contains(DisplayObject(event.target))))))
	    	{
	    		closeDropDown(true);
	    	} 
	    }
	 /**
     *  @private
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
	    protected function systemManager_mouseMoveHandler(event:Event):void {
	        var target:DisplayObject = event.target as DisplayObject;
	        if ((event is MouseEvent && MouseEvent(event).buttonDown) ||
	            (event is SandboxMouseEvent && SandboxMouseEvent(event).buttonDown))
	            return;	        
	        if (target) {	            
	            if (dropDown is DisplayObjectContainer) {
	                if (DisplayObjectContainer(dropDown).contains(target)) return;
	            } else {
	                if (target == dropDown) return;
	            }
	        }	        
	        closeDropDown(true);
	    }
	 /**
     *  @private
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */ 
	    protected function systemManager_resizeHandler(event:Event):void {
	    	closeDropDown(true);
	    }		
	/**
     *  Close the drop down if it is no longer in focus.
     *
     *  @param event The event object for the <code>FOCUS_OUT</code> event.
     * 
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
	    public function processFocusOut(event:FocusEvent):void {
	        if (isOpen) {
	            if (!event.relatedObject ||
	                (!dropDown || 
	                	(dropDown is DisplayObjectContainer &&
	                	 !DisplayObjectContainer(dropDown).contains(event.relatedObject)))) {
	                closeDropDown(true);
	            }
	        }
	    }
	/**
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */    	    
	    public function onTextInputClicked(e:MouseEvent):void{
	    	if (!isOpen){	    			    		
	    		openDropDown();
	    	}
	    }
	 /**
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */ 
	    public function onTextInputChanged(e:TextOperationEvent):void{
	    	if (!isOpen) openDropDown();
	    	dispatchEvent(new AutoCompleteEvent(AutoCompleteEvent.REFILTER, false, true));	    	
	    }
	 /**
     *  Handles the keyboard user interactions.
     *
     *  @param event The event object from the keyboard event.
     * 
     *  @return Returns <code>true</code> if the <code>keyCode</code> was 
     *  recognized and handled.
     * 
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4 
     */	    
		public function processKeyDown(event:KeyboardEvent):Boolean {
	        if (event.ctrlKey && event.keyCode == Keyboard.DOWN) {
	            openDropDown();
	            event.stopPropagation();
	        } else if (event.ctrlKey && event.keyCode == Keyboard.UP) {
	            closeDropDown(true);
	            event.stopPropagation();
	        } else if (event.keyCode == Keyboard.ENTER) {
	            if (isOpen) {
	                closeDropDown(true);
	                event.stopPropagation();
	            }
	        } else if (event.keyCode == Keyboard.ESCAPE) {
	            if (isOpen) {
	                closeDropDown(false);
	                event.stopPropagation();
	            }
	        } else {	        	
	        	return false;
	        }	
	        return true;	    
		}
	}
}